#ifndef frm_control_TTable_H
#define frm_control_TTable_H

#include "frm_control_TCol.h"
#include "frm_control_TFrame.h"

namespace frm { namespace control {

///////////////////////////////////////////////////////////////////////////////
struct TTable;
///////////////////////////////////////////////////////////////////////////////

struct TTableCaption : public TPanel
{
  struct TStyle : public TPanel::TStyle
  {
    svl_Type(TPanel::TStyle)
  };
  //
  svl_Type(TPanel)
  TTableCaption(TTable *Table);
  //
  virtual void TComponent_InheritStyleFrom(TTableOfStyles &ParentStyles);
};

///////////////////////////////////////////////////////////////////////////////

struct TTableGrid : public TPanel
{
  struct TStyle : public TPanel::TStyle
  {
    svl_Type(TPanel::TStyle)
  };
  //
  TTable       *Table;
  //TPanelSelect  PanelSelect;
  //
  svl_Type(TPanel)
  TTableGrid(TTable *Table);
  //
  //TPanel *GetSelect() { return PanelSelect.GetEnter(); }
  //
  virtual void TComponent_KeyboardKey(grf::TKeyboardKey &KeyboardKey);
  //virtual TPanelSelect *TComponent_GetPanelSelect() { return &PanelSelect;}
  virtual void TComponent_InheritStyleFrom(TTableOfStyles &ParentStyles);
  
private:
  svl_Except;
};

////////////////////////////////////////////////////////////////////////////////

struct TTable : public TPanel
{
  struct TStyle : public TPanel::TStyle
  {
    svl_Type(TPanel::TStyle)

    TTableCaption::TStyle Caption;
    TTableGrid::TStyle    Grid;
    //
    virtual void SetFromParent(frm::TStyle *Parent);
    virtual svl::TInfoParam AddInfoTo(svl::TInfoParam Info);
  };
  //
  TTableCaption *Caption;
  TTableGrid    *Grid;
  //
  TTable(TWindow &Window);
 ~TTable();
  //
  svl_Type(TPanel)
  void SetStyle(TStyle &V);
  //
  void SetEnLinkToFrame(bool V = true) { enLinkToFrame = V; }
  void SetMinWidthCols(int V = 20) { minWidthCols = V;}
  void LinkColToGroup(TCol *Col,svl::TString GroupName);
  void UnlinkCol     (TCol *Col);
  //
  virtual void TComponent_InheritStyleFrom(TTableOfStyles &ParentStyles);
  
private:
  struct TCols;
  struct TGroup;
  struct TGroups;
  struct TGroupArray;
  //
  void GetNextCols          (TCol *CurrCol,TCols &NextCols);
  void GetLinkedGroupsByCols(TGroup *Group,TGroupArray &LinkedGroups);
  //
  void UpdateCroupByColSize (TCol *Col,int &ColSize ,TGroup *&OutGroup);
  void UpdateCroupByColRight(TCol *Col,int  ColRight,TGroup *&OutGroup);
  //
  void UpdateCroupBySavedColRight(TCol *Col);
  void UpdateGroups(TCol *CurrCol,int OldCurrColSize,int &NewCurrColSize);
  //
  struct TChangeWidthCol : public geometry::TOrdinate::TEvents
  {
    TTable &Table; TChangeWidthCol(TTable &Table_) : Table(Table_) {}
    virtual void TEvents_BeforeChangeSize(geometry::TOrdinate &Sender,int OldVal,int &NewVal);
  }
  changeWidthCol;
  //
  struct THScrollEvents : public TScrollBar::TEvents
  {
    TTable &Table; THScrollEvents(TTable &Table_) : Table(Table_) {}
    virtual void TEvents_AfterScroll(TI&I,TScrollBar &Sender,int NewPosition);
  }
  *hScrollEvents;
  //
  struct TVScrollEvents : public TScrollBar::TEvents
  {
    TTable &Table; TVScrollEvents(TTable &Table_) : Table(Table_) {}
    virtual void TEvents_AfterScroll(TI&I,TScrollBar &Sender,int NewPosition);
  }
  *vScrollEvents;
  //
  struct TCols 
  {
    int  Count() { return a.Numb();}
    void Clear() { a.Clear();}
    //
    TCol &Get(int N)                { return *(TCol*)a.Get(N);}
    void Add(TCol *V,bool EnDelete) { a.Add(V,EnDelete); }
    void Delete(TCol *V)            { int N; if (Search(V,N)) { a.Delete(N);} }
    bool Search(TCol *V)            { return a.Search(V); }
    bool Search(TCol *V,int &OutN)  { return a.Search(V,OutN); }

  private:
    svl::TArray a;
  };
  //
  struct TGroup : public svl::TBTable_Object , public svl::TArray_Object
  {
    svl::TString Name;
    TCols        Cols;
    int          ColsRight;
    //
    TGroup(char *Name) { this->Name = Name; ColsRight = 0; }
    //
    int  CalcColsRightByConstraint(TTable &Table,int InColRight);
    void UpdateColsRight          (TTable &Table,int InColRight);
    //
    void UpdateBySavedColsRight(TTable &Table);
    //
    virtual int Compare(svl::TBTable_Object *O) { return ::lstrcmpi(Name,((TGroup*)O)->Name);}
    //
    virtual int TArray_Object_Compare(TArray_Object *O) { return ColsRight - ((TGroup*)O)->ColsRight;}
  };
  //
  struct TGroups
  {
    int  Count() { return t.Numb();}
    void Clear() { t.Clear();}
    //
    TGroup &Get   (int N) { return *(TGroup*)t.Get(N);}
    TGroup *Search(char *GroupName) { return (TGroup*)t.Search(TGroup(GroupName));}
    bool    Delete(char *GroupName) { return t.Delete(TGroup(GroupName));}
    void    Insert(TGroup *Group,bool EnDelete) { t.Insert(Group,EnDelete); }
    //
    TGroup *SearchOrInsert(char *GroupName);
    TGroup *SearchGroup(TCol   *Col);
    bool    SearchGroup(TGroup *Group);
    void    CalcGroups (TTable &Table);

  private:
    svl::TBTable t;
  };
  //
  struct TGroupArray 
  {
    int  Count() { return a.Numb();}
    void Clear() { a.Clear();}
    //
    TGroup &Get(int N) { return *(TGroup*)a.Get(N);}
    void    Add(TGroup *Group,bool EnDelete) { a.Add(Group,EnDelete); }
    bool Search(TGroup *Group)               { return a.Search(Group); }
    //
    void SortByColsRight() { a.Sort(); }

  private:
    svl::TArray a;
  };

private:
  virtual void TComponent_AfterCalcAll();
  virtual void TComponent_AddToParent     (TComponent *Parent);
  virtual void TComponent_DeleteFromParent(TComponent *Parent);
  //
  int minWidthCols;
  bool enLinkToFrame;
  TGroups groups;
  friend TTableGrid;
  svl_Except;
};

///////////////////////////////////////////////////////////////////////////////
}}

#endif
